package cron

import (
	"cloudops/src/config"
	"cloudops/src/models"
	"context"
	"fmt"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/nlb"
	"github.com/gammazero/workerpool"
	"github.com/google/uuid"
	"go.uber.org/zap"
	"math/rand"
	"sync"
	"time"
)

func (cm *CronManager) RunSyncCloudResourceElb(ctx context.Context) {
	start := time.Now()

	// 先判断上次同步ELB资源结果
	if !cm.GetElbSynced() {
		cm.Sc.Logger.Info("Start to sync cloud elb resource")
		return
	}
	// 上次完成，就开始新的一次同步
	cm.SetElbSynced(false)

	// 同步云上的ELB所以资源
	wp := workerpool.New(5)
	allMap := sync.Map{}
	for _, alic := range cm.Sc.PublicCloudSyncC.AliCloud {
		alic := alic
		wp.Submit(func() {
			// 启动任务
			cm.RunSyncOneCloudElbAli(alic, &allMap)
		})
	}
	wp.StopWait()

	//计算 to_add to_del to_mod
	toAddSet := make([]*models.ResourceElb, 0)
	toModSet := make([]*models.ResourceElb, 0)
	toDelUids := []string{}
	localUidSet := make(map[string]struct{})

	var toAddNum, toModNum, toDelNum int
	var suAddNum, suModNum, suDelNum int

	// 获取本地的uid对应的hashM
	dbUidHashM, err := models.GetResourceElbUidAndHash()
	if err != nil {
		cm.Sc.Logger.Error("ELB sync get local uid hash error", zap.Error(err))
		return
	}

	// 获取云上的uid对应的hashM
	rangeFunc := func(k, v interface{}) bool {
		uid := k.(string)
		reourceObj := v.(*models.ResourceElb)
		localUidSet[uid] = struct{}{}

		dbHash, ok := dbUidHashM[uid]
		if !ok {
			toAddSet = append(toAddSet, reourceObj)
			toAddNum++
		} else {
			// 对比hash
			if dbHash != reourceObj.Hash {
				toModSet = append(toModSet, reourceObj)
				toModNum++
			}
		}
		return true
	}
	allMap.Range(rangeFunc)
	// 获取本地没有的uid
	for _, obj := range toAddSet {
		err := obj.Create()
		if err != nil {
			cm.Sc.Logger.Error("ELB sync create error",
				zap.Error(err),
				zap.Any("id", obj.InstanceId),
				zap.Any("name", obj.InstanceName),
			)
			continue
		}
		cm.Sc.Logger.Info("ELB sync create success",
			zap.Any("id", obj.InstanceId),
			zap.Any("name", obj.InstanceName),
		)
		suAddNum++
	}

	// 更新
	for _, obj := range toModSet {
		err := obj.UpdateOne()
		if err != nil {
			cm.Sc.Logger.Error("ELB sync update error",
				zap.Error(err),
				zap.Any("id", obj.InstanceId),
				zap.Any("name", obj.InstanceName),
			)
			continue
		}
		cm.Sc.Logger.Info("ELB sync update success",
			zap.Any("id", obj.InstanceId),
			zap.Any("name", obj.InstanceName),
		)
		suModNum++
	}

	// 删除
	for _, uid := range toDelUids {
		// 先找到这个对象
		dbOjb, err := models.GetResourceElbByInstanceId(uid)
		if err != nil {
			cm.Sc.Logger.Error("ELB Query delete error",
				zap.Error(err),
				zap.Any("id", uid),
			)
			continue
		}
		err = dbOjb.DeleteOne()
		if err != nil {
			cm.Sc.Logger.Error("ELB sync delete error",
				zap.Error(err),
				zap.Any("id", uid),
			)
			continue
		}
		cm.Sc.Logger.Info("ELB  delete success",
			zap.Any("id", uid),
		)
		suDelNum++
	}
	// 统计耗时
	tookSeconds := time.Since(start).Seconds()
	cm.Sc.Logger.Info("同步elb结果打印",
		zap.Any("公有云总数", len(localUidSet)),
		zap.Any("数据库", len(dbUidHashM)),
		zap.Any("toAddNum", toAddNum),
		zap.Any("toModNum", toModNum),
		zap.Any("toDelNum", toDelNum),
		zap.Any("suAddNum", suAddNum),
		zap.Any("suModNum", suModNum),
		zap.Any("suDelNum", suDelNum),
		zap.Any("timeTook", tookSeconds),
	)

	// 本地同步结束 标记完成
	cm.SetElbSynced(true)
}

func (cm *CronManager) RunSyncOneCloudElbAli(alic *config.AliCloud, allMap *sync.Map) {
	cm.Sc.Logger.Info("开始同步阿里云ELB",
		zap.Any("地区", alic.RegionId),
		zap.Any("accessKeyId", alic.AccessKeyId),
		zap.Any("accessKeySecret", alic.AccessKeySecret),
	)

	// mock返回数据
	rand.Seed(time.Now().UnixNano())
	allNum := MockElbListElbResponse(allMap)
	cm.Sc.Logger.Info("阿里云ELB同步完成",
		zap.Any("地区", alic.RegionId),
		zap.Any("accessKeyId", alic.AccessKeyId),
		zap.Any("accessKeySecret", alic.AccessKeySecret),
		zap.Any("数量", allNum),
	)
	return

	// 新建elb client
	client, err := nlb.NewClientWithAccessKey(
		alic.RegionId,
		alic.AccessKeyId,
		alic.AccessKeySecret,
	)
	if err != nil {
		cm.Sc.Logger.Error("ali cloud ELB client create error",
			zap.Any("地区", alic.RegionId),
			zap.Any("accessKeyId", alic.AccessKeyId),
			zap.Any("accessKeySecret", alic.AccessKeySecret),
		)
		return
	}
	cm.Sc.Logger.Info("ali cloud elb client create success", zap.Any("client", client.Client))
	resp, err := client.ListLoadBalancers(&nlb.ListLoadBalancersRequest{})
	if err != nil {
		cm.Sc.Logger.Error("nlb ListLoadBanlancer error",
			zap.Error(err),
			zap.Any("RegionId", alic.RegionId),
			zap.Any("accessKeyId", alic.AccessKeyId),
			zap.Any("accessKeySecret", alic.AccessKeySecret),
		)
		return
	}
	cm.Sc.Logger.Info("nlb ListLoadBanlancer success",
		zap.Int("elb", resp.TotalCount),
		zap.Any("RegionId", alic.RegionId),
		zap.Any("accessKeyId", alic.AccessKeyId),
		zap.Any("accessKeySecret", alic.AccessKeySecret),
	)
	cloudIns := resp.LoadBalancers
	for _, ins := range cloudIns {
		dbIns := cm.ConvertElbCloudAli(ins)
		allMap.Store(ins.LoadBalancerId, dbIns)
	}
	return
}

func MockElbListElbResponse(allMap *sync.Map) int {
	rand.Seed(time.Now().UnixNano())
	// 公共的
	randEnv := []string{"dev", "press", "stage", "prod"}
	randVendor := []string{"阿里云", "华为云", "腾讯云", "aws", "世纪互联"}
	randVpcId := []string{"vpc-01", "vpc-02", "vpc-03"}
	randZoneId := []string{"bj1", "bj4", "hangzhou1", "sh1", "sh3"}
	// 标签tags
	randTagKeys := []string{"arch", "idc", "os", "job", "env", "cluster", "type"}
	randTagValues := []string{"linux", "beijing", "windows", "shanghai", "arm64", "amd64", "darwin", "shijihulian"}

	// 独特的
	randLoadBalancerType := []string{"alb", "clb", "nlb"}
	randDNSName := []string{"win10", "ubuntu", "centos", "Eurla", "debian"}
	randBandwidthCapacity := []int{50, 100, 200, 500, 1000, 2000}

	// 目的是4选1 返回0-3的数组
	// 比如8-15 15-8 +8
	frn := func(n int) int {
		rand.Seed(time.Now().UnixNano())
		return rand.Intn(n)
	}

	// 每次host数量 10-30个
	frNum := func() int {
		rand.Seed(time.Now().UnixNano())
		return int(rand.Int63n(40-20) + 10)
	}
	all := 0
	// 每次固定的实例，它的uid 要一致
	for i := 0; i < 100; i++ {
		objOne := &models.ResourceElb{}

		// 固定id
		objOne.InstanceId = fmt.Sprintf("elb-id-fixed-%v", i)
		objOne.InstanceName = fmt.Sprintf("elb-name-fixed-%v", i)

		// 公共字段
		objOne.Env = randEnv[frn(len(randEnv)-1)]
		objOne.Vendor = randVendor[frn(len(randVendor)-1)]
		objOne.ZoneId = randZoneId[frn(len(randZoneId)-1)]
		objOne.VpcId = randVpcId[frn(len(randVpcId)-1)]
		tags := []string{}
		for _, tagKey := range randTagKeys {
			tagValue := randTagValues[frn(len(randTagValues)-1)]
			oneTag := fmt.Sprintf("%s=%s", tagKey, tagValue)
			tags = append(tags, oneTag)
		}
		objOne.Tags = tags

		innerIp := fmt.Sprintf("1%v.%v.%v.%v", i, i, i, i)
		pubIp := fmt.Sprintf("2%v.%v.%v.%v", i, i, i, i)

		objOne.PrivateIpAddress = []string{innerIp}
		objOne.PublicIpAddress = []string{pubIp}

		// 独特字段
		objOne.LoadBalancerType = randLoadBalancerType[frn(len(randLoadBalancerType)-1)]
		objOne.BandwidthCapacity = randBandwidthCapacity[frn(len(randBandwidthCapacity)-1)]
		objOne.DNSName = fmt.Sprintf("%s.dev.com", randDNSName[frn(len(randDNSName)-1)])

		objOne.Hash = objOne.GenHash()
		allMap.Store(objOne.InstanceId, objOne)
		all++
	}

	// 下面是纯随机的
	for i := 0; i < frNum(); i++ {
		objOne := &models.ResourceElb{}

		objOne.InstanceId = uuid.New().String()
		objOne.InstanceName = fmt.Sprintf("elb-name-%v-%v", i, objOne.InstanceId[:10])

		// 公共字段
		objOne.Env = randEnv[frn(len(randEnv)-1)]
		objOne.Vendor = randVendor[frn(len(randVendor)-1)]
		objOne.VpcId = randVpcId[frn(len(randVpcId)-1)]
		tags := []string{}
		for _, tagKey := range randTagKeys {
			tagValue := randTagValues[frn(len(randTagValues)-1)]
			oneTag := fmt.Sprintf("%s=%s", tagKey, tagValue)
			tags = append(tags, oneTag)
		}
		objOne.Tags = tags

		innerIp := fmt.Sprintf("1%v.%v.%v.%v", i, i, i, i)
		pubIp := fmt.Sprintf("2%v.%v.%v.%v", i, i, i, i)
		objOne.PrivateIpAddress = []string{innerIp}
		objOne.PublicIpAddress = []string{pubIp}

		// 独特字段
		objOne.LoadBalancerType = randLoadBalancerType[frn(len(randLoadBalancerType)-1)]
		objOne.BandwidthCapacity = randBandwidthCapacity[frn(len(randBandwidthCapacity)-1)]
		objOne.DNSName = fmt.Sprintf("%s.dev.com", randDNSName[frn(len(randDNSName)-1)])

		objOne.Hash = objOne.GenHash()
		allMap.Store(objOne.InstanceId, objOne)
		all++
	}
	return all
}

func (cm *CronManager) ConvertElbCloudAli(ins nlb.LoadbalancerInfo) *models.ResourceEcs {
	return nil
}
